package dkbta;

import static dkbta.util.Utils.isEmpty;
import static dkbta.util.Utils.readDOMDocFromXML;

import java.io.File;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import dkbta.processing.PlanException;
import dkbta.processing.UnitPorts;

public class CoordinatorConfig{
	private static final String CONFIG_FILE_NAME = "Coordinator.xml";
	private static Element coordinatorPlan;
	private static String inputFileName;
	
	static{
		try{
			coordinatorPlan = readDOMDocFromXML(new File(CONFIG_FILE_NAME)).getDocumentElement();
			}
		catch(Exception e){
			
			System.err.println("Unable to load configuration from: " + CONFIG_FILE_NAME);
			e.printStackTrace();
		}
	}
	public static String getPlanMakerName() throws PlanException{
		Element planMakerElement = getXmlElement(coordinatorPlan, "PlanMaker");
		if (planMakerElement == null){
			throw new PlanException("There is no 'Plan Maker' element");
		}
		return planMakerElement.getAttribute("name");
	}
	
	public static boolean isUnits() throws PlanException{
		Element unitsEnableElement = getXmlElement(coordinatorPlan, "UnitsEnable");
		if (unitsEnableElement == null){
			throw new PlanException("There is no 'Units Enable' element");
		}
		String value = unitsEnableElement.getAttribute("isEnable");
		return value == null ? false : Boolean.parseBoolean(value);
	}
	
	public static boolean isFileInput() throws PlanException{
		Element fileInfoElement = getXmlElement(coordinatorPlan, "TasksSender");
		if (fileInfoElement == null){
			throw new PlanException("There is no 'File Info' element");
		}
		String value = fileInfoElement.getAttribute("inputFromFile");
		inputFileName = fileInfoElement.getAttribute("fileName");
		return (value == null ? true : Boolean.parseBoolean(value));
	}
	
	private static InetSocketAddress getInetSocketAddress(String name) throws PlanException{
		Element serverElement = getXmlElement(coordinatorPlan, name);
		if (serverElement == null){
			throw new PlanException("There is no '" + name + "' element");
		}

		String ip = serverElement.getAttribute("ip");
		if (isEmpty(ip)){
			throw new PlanException("Invalid ip '" + ip + "' of the " + name);
		}

		String portStr = serverElement.getAttribute("port");
		int port;
		try{
			port = Integer.valueOf(portStr);
		}catch(NumberFormatException e){
			throw new PlanException("Invalid port '" + portStr + "' of the " + name);
		}
		return new InetSocketAddress(ip, port);
	}
	
	public static InetSocketAddress getTaskServerAddress() throws PlanException{
		return getInetSocketAddress("TasksServer");
	}
	
	public static InetSocketAddress getCoordinatorServerAddress() throws PlanException{
		return getInetSocketAddress("Coordinator");
	}
	
	public static String getTaskFileName(){
		return inputFileName;
	}
	
	public static Element getXmlElement(Element parent, String tagName) throws PlanException{
		
		NodeList nodes = parent.getElementsByTagName(tagName);
		if (nodes.getLength() == 0){
			return null;
		}
		if (nodes.getLength() != 1){
			throw new PlanException("Multile '" + tagName + "' elements");
		}
		
		return (Element)nodes.item(0);
		}
	
	public static Map<Integer, UnitPorts> getUnits() throws PlanException{
		Element unitsElement = getXmlElement(coordinatorPlan, "Units");
		if (unitsElement == null){
			throw new PlanException("There is no 'Units' element");
		}

		NodeList unitNodes = unitsElement.getElementsByTagName("Unit");
		int length = unitNodes.getLength();
		if (length == 0){
			throw new PlanException(
					"There are no 'Unit' elements inside the 'Units' element");
		}

		Map<Integer, UnitPorts> units = new HashMap<Integer, UnitPorts>(length);
		for (int i = 0; i < length; ++i){
			Element unit = (Element)unitNodes.item(i);

			// Parsing the unit id
			String idStr = unit.getAttribute("id");
			int id;
			try{
				id = Integer.valueOf(idStr);
			}catch(NumberFormatException e){
				throw new PlanException("Invalid unit id: " + idStr);
			}

			// Parsing the unit's ip/hostname
			String ip = unit.getAttribute("ip");
			if (isEmpty(ip)){
				throw new PlanException("Invalid ip '" + ip + "' of unit #" + id);
			}

			// Parsing the unit's data port
			String dataPortStr = unit.getAttribute("dataPort");
			int dataPort;
			try{
				dataPort = Integer.valueOf(dataPortStr);
			}catch(NumberFormatException e){
				throw new PlanException("Invalid data port '" + dataPortStr
						+ "' of unit #" + id);
			}

			// Parsing the unit's data port
			String controlPortStr = unit.getAttribute("controlPort");
			int controlPort;
			try{
				controlPort = Integer.valueOf(controlPortStr);
			}catch(NumberFormatException e){
				throw new PlanException("Invalid control port '" + controlPortStr
						+ "' of unit #" + id);
			}
			units.put(id, new UnitPorts(new InetSocketAddress(ip, dataPort),
					new InetSocketAddress(ip, controlPort)));
		}

		return units;
	}
}
